#include "mpeg4avc.h"
#include <stdio.h>
#include <string.h>
#include <assert.h>

#define H264_NAL_IDR		5     // IDR帧图像编码切片
#define H264_NAL_SPS		7     // 序列参数及
#define H264_NAL_PPS		8     // 图像参数集
#define H264_NAL_AUD		9     // 访问单元分隔符

#define H2645_BITSTREAM_FORMAT_DETECT
#define H264_STARTCODE(p) (p[0]==0 && p[1]==0 && (p[2]==1 || (p[2]==0 && p[3]==1)))
struct h264_annexbtomp4_handle_t     // annexb转成MP4
{
	struct mpeg4_avc_t* avc;
	int errcode;
	int* update;    // avc sps/pps update flags
	int* vcl;       // 记录NAL类型

	uint8_t* out;     // 指向的是缓存区的地址
	size_t bytes;     // 记录out已经使用了的大小
	size_t capacity;  // 记录out的容量
};


int mpeg4_avc_decoder_configuration_record_load(const uint8_t* data, size_t bytes, struct mpeg4_avc_t* avc)
{
    uint8_t i;
	uint32_t j;
	uint16_t len;
    uint8_t *p, *end;

	if (bytes < 7) return -1;
	assert(1 == data[0]);
//	avc->version = data[0];
	avc->profile = data[1];
	avc->compatibility = data[2];
	avc->level = data[3];
	avc->nalu = (data[4] & 0x03) + 1;
	avc->nb_sps = data[5] & 0x1F;
	if (avc->nb_sps > sizeof(avc->sps) / sizeof(avc->sps[0]))
	{
		assert(0);
		return -1; // sps <= 32
	}

	j = 6;
    p = avc->data;
    end = avc->data + sizeof(avc->data);
	for (i = 0; i < avc->nb_sps && j + 2 < bytes; ++i)
	{
		len = (data[j] << 8) | data[j + 1];
		if (j + 2 + len >= bytes || p + len > end)
		{
			assert(0);
			return -1;
		}
		memcpy(p, data + j + 2, len);
        avc->sps[i].data = p;
		avc->sps[i].bytes = len;
		j += len + 2;
        p += len;
	}

	if (j >= bytes || (unsigned int)data[j] > sizeof(avc->pps) / sizeof(avc->pps[0]))
	{
		assert(0);
		return -1;
	}

	avc->nb_pps = data[j++]; 
	for (i = 0; i < avc->nb_pps && j + 2 < bytes; i++)
	{
		len = (data[j] << 8) | data[j + 1];
        if (j + 2 + len > bytes || p + len > end)
        {
            assert(0);
            return -1;
        }
		memcpy(p, data + j + 2, len);
        avc->pps[i].data = p;
		avc->pps[i].bytes = len;
		j += len + 2;
        p += len;
	}

	avc->off = (int)(p - avc->data);
	return j;
}
// 将non-vcl解码参数拷贝到缓存区中
int mpeg4_avc_decoder_configuration_record_save(const struct mpeg4_avc_t* avc, uint8_t* data, size_t bytes)
{
	uint8_t i;
	uint8_t *p = data;    // 缓存区

	assert(0 < avc->nalu && avc->nalu <= 4);
	if (bytes < 7 || avc->nb_sps > 32) return -1;
	bytes -= 7;
    /* 将这一帧数据的元数据写入缓存区 */
	p[0] = 1; 
	p[1] = avc->profile; 
	p[2] = avc->compatibility; 
	p[3] = avc->level;     //
	p[4] = 0xFC | (avc->nalu - 1);     // 1111 1100 记录nal长度
	p += 5;
	// sps
	*p++ = 0xE0 | avc->nb_sps;   // 1110 0000  用低五位记录sps个数
	for (i = 0; i < avc->nb_sps && bytes >= (size_t)avc->sps[i].bytes + 2; i++)
	{
		/* 挨个进行缓存 SPS （大小 + 数据）*/
		*p++ = (avc->sps[i].bytes >> 8) & 0xFF;
		*p++ = avc->sps[i].bytes & 0xFF; /**/
		memcpy(p, avc->sps[i].data, avc->sps[i].bytes);   // 记录每一个SPS大小
        /* 数据拷贝到缓存区后，偏移对应的位置*/
		p += avc->sps[i].bytes;    // 偏移位置留着放sps
		bytes -= avc->sps[i].bytes + 2;   // 更新sps大小
	}
	if (i < avc->nb_sps) return -1; 

	// pps
	*p++ = avc->nb_pps;
	for (i = 0; i < avc->nb_pps && bytes >= (size_t)avc->pps[i].bytes + 2; i++)
	{
		*p++ = (avc->pps[i].bytes >> 8) & 0xFF;
		*p++ = avc->pps[i].bytes & 0xFF;
		memcpy(p, avc->pps[i].data, avc->pps[i].bytes);     // 记录每一个 pps  大小

		p += avc->pps[i].bytes;     // 偏移位置留着放pps
		bytes -= avc->pps[i].bytes + 2;
	}
	if (i < avc->nb_pps) return -1;
	/*    往缓存区里面推扩展数据   */
	if (bytes >= 4)
	{
		if (avc->profile == 100 || avc->profile == 110 ||
			avc->profile == 122 || avc->profile == 244 || avc->profile == 44 ||
			avc->profile == 83 || avc->profile == 86 || avc->profile == 118 ||
			avc->profile == 128 || avc->profile == 138 || avc->profile == 139 ||
			avc->profile == 134)
		{
			*p++ = 0xFC | avc->chroma_format_idc;
			*p++ = 0xF8 | avc->bit_depth_luma_minus8;
			*p++ = 0xF8 | avc->bit_depth_chroma_minus8;
			*p++ = 0; 
		}
	}
	/* 返回写入多少数据*/
	return (int)(p - data);    // sps  pps 占用的大小
}


int mpeg4_avc_to_nalu(const struct mpeg4_avc_t* avc, uint8_t* data, size_t bytes)
{
	uint8_t i;
	size_t k = 0;
	uint8_t* h264 = data;

	// sps
	for (i = 0; i < avc->nb_sps && bytes >= k + avc->sps[i].bytes + 4; i++)
	{
		if (avc->sps[i].bytes < 4 || !H264_STARTCODE(avc->sps[i].data))
		{
			h264[k++] = 0;
			h264[k++] = 0;
			h264[k++] = 0;
			h264[k++] = 1;
		}
		memcpy(h264 + k, avc->sps[i].data, avc->sps[i].bytes);

		k += avc->sps[i].bytes;
	}
	if (i < avc->nb_sps) return -1; // check length

	// pps
	for (i = 0; i < avc->nb_pps && bytes >= k + avc->pps[i].bytes + 2; i++)
	{
		if (avc->pps[i].bytes < 4 || !H264_STARTCODE(avc->pps[i].data))
		{
			h264[k++] = 0;
			h264[k++] = 0;
			h264[k++] = 0;
			h264[k++] = 1;
		}
		memcpy(h264 + k, avc->pps[i].data, avc->pps[i].bytes);

		k += avc->pps[i].bytes;
	}
	if (i < avc->nb_pps) return -1; // check length

	assert(k < 0x7FFF);
	return (int)k;
}

int mpeg4_avc_codecs(const struct mpeg4_avc_t* avc, char* codecs, size_t bytes)
{
    return snprintf(codecs, bytes, "avc1.%02x%02x%02x", avc->profile, avc->compatibility, avc->level);
}


void mpeg4_avc_test(void)
{
	const unsigned char src[] = {
		0x01,0x42,0xe0,0x1e,0xff,0xe1,0x00,0x21,0x67,0x42,0xe0,0x1e,0xab,0x40,0xf0,0x28,
		0xd0,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x19,0x70,0x20,0x00,0x78,0x00,0x00,0x0f,
		0x00,0x16,0xb1,0xb0,0x3c,0x50,0xaa,0x80,0x80,0x01,0x00,0x04,0x28,0xce,0x3c,0x80
	};
	const unsigned char nalu[] = {
		0x00,0x00,0x00,0x01,0x67,0x42,0xe0,0x1e,0xab,0x40,0xf0,0x28,0xd0,0x80,0x00,0x00,
		0x00,0x80,0x00,0x00,0x19,0x70,0x20,0x00,0x78,0x00,0x00,0x0f,0x00,0x16,0xb1,0xb0,
		0x3c,0x50,0xaa,0x80,0x80,0x00,0x00,0x00,0x01,0x28,0xce,0x3c,0x80
	};
	unsigned char data[sizeof(src)];

	struct mpeg4_avc_t avc;
	assert(sizeof(src) == mpeg4_avc_decoder_configuration_record_load(src, sizeof(src), &avc));
	assert(0x42 == avc.profile && 0xe0 == avc.compatibility && 0x1e == avc.level);
	assert(4 == avc.nalu && 1 == avc.nb_sps && 1 == avc.nb_pps);
	assert(sizeof(src) == mpeg4_avc_decoder_configuration_record_save(&avc, data, sizeof(data)));
	assert(0 == memcmp(src, data, sizeof(src)));
    mpeg4_avc_codecs(&avc, (char*)data, sizeof(data));
    assert(0 == memcmp("avc1.42e01e", data, 11));

	assert(sizeof(nalu) == mpeg4_avc_to_nalu(&avc, data, sizeof(data)));
	assert(0 == memcmp(nalu, data, sizeof(nalu)));

	mpeg4_annexbtomp4_test();
}


static const uint8_t* h264_startcode(const uint8_t *data, size_t bytes)
{
	size_t i;
	for (i = 2; i + 1 < bytes; i++)
	{
		if (0x01 == data[i] && 0x00 == data[i - 1] && 0x00 == data[i - 2])
			return data + i + 1;    // 找三字节的起始码 ；并将NAL数据部分的地址返回回去
	}
	return NULL;   
}

///   获取NAL大小
static inline int h264_avcc_length(const uint8_t* h264, size_t bytes, size_t avcc)
{
	size_t i;
	uint32_t n;

	n = 0;
	assert(3 <= avcc && avcc <= 4);
	for (i = 0; i < avcc && i < bytes; i++)
		n = (n << 8) | h264[i];     // 获取NAL的字节大小
	return avcc >= bytes ? -1 : (int)n;    // 返回获取的NAL大小
}

/// --------------检查 stream 网络层是不是采用的 avcc 的封装
static int mpeg4_h264_avcc_bitstream_valid(const uint8_t* h264, size_t bytes, size_t avcc)    // avcc 4 avcc 的起始码固定4字节 表示下一个NAL大小
{
	size_t n;

	while(avcc + 1 < bytes)    // 遍历整个文件NALU
	{
		n = h264_avcc_length(h264, bytes, avcc);     // avcc NAL size
		if (n < 0 || n + avcc > bytes) //  start code + NAL 和 文件数据大小比较
			return 0; // invalid

		h264 += n + avcc;     //  数据偏移到下一个NUL中
		bytes -= n + avcc;    //  移到下一个NUL中
	}

	return 0 == bytes ? 1 : 0;      // 1 代表这个文件流是avcc的编码封装格式；否则不是
}

static int mpeg4_h264_avcc_nalu(const void* h264, size_t bytes, int avcc, void (*handler)(void* param, const uint8_t* nalu, size_t bytes), void* param)
{
	uint32_t n;
	const uint8_t* p, * end;

	p = (const uint8_t*)h264;
	end = (const uint8_t*)h264 + bytes;
	// 
	for(n = h264_avcc_length(p, (int)(end - p), avcc); p + n + avcc <= end; n = h264_avcc_length(p, (int)(end - p), avcc))
	{
		assert(n > 0);
		if (n > 0)
		{
			handler(param, p + avcc, (int)n);
		}
		p += n + avcc;   // 跳到下一个 NAL 块
	}
	return 0;
}

/// return 0-annexb, >0-avcc, <0-error     // start code | NALU | strat code | NALU | *** *** 
int mpeg4_h264_bitstream_format(const uint8_t* h264, size_t bytes)
{
	uint32_t n;
	if (bytes < 4)
		return -1;

	n = ((uint32_t)h264[0]) << 16 | ((uint32_t)h264[1]) << 8 | ((uint32_t)h264[2]);    //     ------   起始码 001  或则 0001    
	if (0 == n && h264[3] <= 1)    // 起始位 四位的时候
	{
		return 0; 				   // annexb    说明这个视频文件的网络层封装是ANNEX B的封装格式
	}
	else if(1 == n)    			   // 三位 起始 码   
	{
		// try avcc & annexb   
		return mpeg4_h264_avcc_bitstream_valid(h264, bytes, 4) ? 4 : 0;    // 判断裸流是不是avcc封装的NAL
	}
	else     // AVCC 封装的  NAL      AVCC start code is 4bit ;but is NAL byte number
	{
		// 一般情况下，都是使用的4字节来表示NAL大小；内存对齐问题；三字节的基本没有了
		return mpeg4_h264_avcc_bitstream_valid(h264, bytes, 4) ? 4 : (mpeg4_h264_avcc_bitstream_valid(h264, bytes, 3) ? 3 : -1);  // 判断裸流中avcc封装的起始位使用的是3位还是四位
	}
}
uint8_t mpeg4_h264_read_ue(const uint8_t* data, size_t bytes, size_t* offset)
{
	int bit, i;
	int leadingZeroBits = -1;

	for (bit = 0; !bit && *offset / 8 < bytes; ++leadingZeroBits)
	{
		bit = (data[*offset / 8] >> (7 - (*offset % 8))) & 0x01;
		++*offset;
	}

	bit = 0;
	assert(leadingZeroBits < 32);
	for (i = 0; i < leadingZeroBits && *offset / 8 < bytes; i++)
	{
		bit = (bit << 1) | ((data[*offset / 8] >> (7 - (*offset % 8))) & 0x01);
		++*offset;
	}

	return (uint8_t)((1 << leadingZeroBits) - 1 + bit);
}


///@param[in] h264 H.264 byte stream format data(A set of NAL 单元)
/*
  功能：
  参数：
		h264：文件中的 264 裸流
		bytes： 裸流大小，总共有多少数据
		handler：回调，将264的裸流封装到 MP4 中
*/
int mpeg4_h264_annexb_nalu(const void* h264, size_t bytes, void (*handler)(void* param, const uint8_t* nalu, size_t bytes), void* param)
{
	ptrdiff_t n;
	const uint8_t* p, *next, *end;

#if defined(H2645_BITSTREAM_FORMAT_DETECT)
	int avcc;
	avcc = mpeg4_h264_bitstream_format(h264, bytes);    // 传入裸流数据；获取裸流的NAL封装是采用的什么格式封装 ANNEXB 和 AVCC的哪种

	if (avcc > 0)  // 确定就是AVCC了
		return mpeg4_h264_avcc_nalu(h264, bytes, avcc, handler, param);
#endif

	end = (const uint8_t*)h264 + bytes;   /* 记录裸流的末尾位置 */
	p = h264_startcode((const uint8_t*)h264, bytes);     // 找到当前起始码的NAL数据首地址

	while (p)    // 如果是三字节的起始码；返回起始码的位置;input while
	{
		next = h264_startcode(p, (int)(end - p));   // 找下一个起始码之后的NAL数据的首地址
		if (next)
		{
			n = next - p - 3;   // 获取next指向的前一个的 NAL 纯数据大小
		}
		else
		{
			n = end - p;   // 四字节的起始码的位置；说明读取到最后一个NAL上了
		}
		while (n > 0 && 0 == p[n - 1]) n--; // 过滤当前NAL的尾部的0
		assert(n > 0);
		if (n > 0)    /* 如果还存在数据 */
		{
			handler(param, p, (int)n);      // 传入当前的ANNEX B 的nal单元 同时传入ctx里面 
		}

		p = next;   // 移动NAL
	}

	return 0;
}

static void mpeg4_avc_remove(struct mpeg4_avc_t* avc, uint8_t* ptr, size_t bytes, const uint8_t* end)
{
	uint8_t i;
	assert(ptr >= avc->data && ptr + bytes <= end && end <= avc->data + sizeof(avc->data));
	memmove(ptr, ptr + bytes, end - ptr - bytes);

	for (i = 0; i < avc->nb_sps; i++)
	{
		if (avc->sps[i].data > ptr)
			avc->sps[i].data -= bytes;
	}

	for (i = 0; i < avc->nb_pps; i++)
	{
		if (avc->pps[i].data > ptr)
			avc->pps[i].data -= bytes;
	}
}

static int h264_sps_copy(struct mpeg4_avc_t* avc, const uint8_t* nalu, size_t bytes)
{
	size_t i;
	size_t offset;
    uint8_t spsid;

	if (bytes < 4 + 1)
	{
		assert(0);
		return -1; // invalid length
	}

	offset = 4 * 8; // 1-NALU + 3-profile+flags+level
	spsid = mpeg4_h264_read_ue(nalu, bytes, &offset);

	for (i = 0; i < avc->nb_sps; i++)
	{
		offset = 4 * 8; // reset offset
		if (spsid == mpeg4_h264_read_ue(avc->sps[i].data, avc->sps[i].bytes, &offset))
		{
			if (bytes == avc->sps[i].bytes && 0 == memcmp(nalu, avc->sps[i].data, bytes))
				return 0; // do nothing

			if (bytes > avc->sps[i].bytes && avc->off + (bytes - avc->sps[i].bytes) > sizeof(avc->data))
			{
				assert(0);
				return -1; // too big
			}

			mpeg4_avc_remove(avc, avc->sps[i].data, avc->sps[i].bytes, avc->data + avc->off);
			avc->off -= avc->sps[i].bytes;

			avc->sps[i].data = avc->data + avc->off;
			avc->sps[i].bytes = (uint16_t)bytes;
			memcpy(avc->sps[i].data, nalu, bytes);
			avc->off += bytes;
			return 1; // set update flag
		}
	}

	// copy new
	assert(avc->nb_sps < sizeof(avc->sps) / sizeof(avc->sps[0]));
	if (avc->nb_sps >= sizeof(avc->sps) / sizeof(avc->sps[0])
		|| avc->off + bytes > sizeof(avc->data))
	{
		assert(0);
		return -1;
	}

	avc->sps[avc->nb_sps].data = avc->data + avc->off;
	avc->sps[avc->nb_sps].bytes = (uint16_t)bytes;
	memcpy(avc->sps[avc->nb_sps].data, nalu, bytes);
	avc->off += bytes;
	++avc->nb_sps;
	return 1; // set update flag
}

static int h264_pps_copy(struct mpeg4_avc_t* avc, const uint8_t* nalu, size_t bytes)
{
	size_t i;
    size_t offset;
	uint8_t spsid;
	uint8_t ppsid;

	if (bytes < 1 + 1)
	{
		assert(0);
		return -1; // invalid length
	}

	offset = 1 * 8; // 1-NALU
	ppsid = mpeg4_h264_read_ue(nalu, bytes, &offset);
	spsid = mpeg4_h264_read_ue(nalu, bytes, &offset);

	for (i = 0; i < avc->nb_pps; i++)
	{
		offset = 1 * 8; // reset offset
		if (ppsid == mpeg4_h264_read_ue(avc->pps[i].data, avc->pps[i].bytes, &offset) && spsid == mpeg4_h264_read_ue(avc->pps[i].data, avc->pps[i].bytes, &offset))
		{
			if (bytes == avc->pps[i].bytes && 0 == memcmp(nalu, avc->pps[i].data, bytes))
				return 0; // do nothing

			if (bytes > avc->pps[i].bytes && avc->off + (bytes - avc->pps[i].bytes) > sizeof(avc->data))
			{
				assert(0);
				return -1; // too big
			}

			mpeg4_avc_remove(avc, avc->pps[i].data, avc->pps[i].bytes, avc->data + avc->off);
			avc->off -= avc->pps[i].bytes;

			avc->pps[i].data = avc->data + avc->off;
			avc->pps[i].bytes = (uint16_t)bytes;
			memcpy(avc->pps[i].data, nalu, bytes);
			avc->off += bytes;
			return 1; // set update flag
		}
	}

	// copy new
	assert((unsigned int)avc->nb_pps < sizeof(avc->pps) / sizeof(avc->pps[0]));
	if ((unsigned int)avc->nb_pps >= sizeof(avc->pps) / sizeof(avc->pps[0])
		|| avc->off + bytes > sizeof(avc->data))
	{
		assert(0);
		return -1;
	}

	avc->pps[avc->nb_pps].data = avc->data + avc->off;
	avc->pps[avc->nb_pps].bytes = (uint16_t)bytes;
	memcpy(avc->pps[avc->nb_pps].data, nalu, bytes);
	avc->off += bytes;
	++avc->nb_pps;
	return 1; // set update flag
}

static int mpeg4_avc_update(struct mpeg4_avc_t* avc, const uint8_t* nalu, size_t bytes)
{
	int r;
	
	switch (nalu[0] & 0x1f)    // 判断NAL类型
	{
	case H264_NAL_SPS:
		r = h264_sps_copy(avc, nalu, bytes);    // 拷贝sps
		if (1 == avc->nb_sps)
		{
			// update profile/level once only
			avc->profile = nalu[1];   
			avc->compatibility = nalu[2]; 
			avc->level = nalu[3]; 
		}
		break;

	case H264_NAL_PPS:
		r = h264_pps_copy(avc, nalu, bytes);      // 拷贝pps
		break;

	default:
		r = 0;
	}

	return r;
}
/*
功能：获取单个NALU，判断是元数据还是帧数据，
  param： h264_annexbtomp4_handle_t 结构体对象
  nalu： 一组 NALU（| SPS | PPS | SEI | VCL | VCL | VCL |）中的一个
  bytes：这个 NALU 的大小
*/
static void h264_handler(void* param, const uint8_t* nalu, size_t bytes)
{
	int r;
	uint8_t nalutype;
	struct h264_annexbtomp4_handle_t* mp4;
	mp4 = (struct h264_annexbtomp4_handle_t*)param;
	if (bytes < 1)
	{
		assert(0);
		return;
	}

	nalutype = (nalu[0]) & 0x1f;    // 判断NAL的类型
#if defined(H2645_FILTER_AUD)
	if (H264_NAL_AUD == nalutype)
		return; // ignore AUD
#endif
    /* 更新当前帧的 元数据 */
	r = mpeg4_avc_update(mp4->avc, nalu, bytes);   // 判断这个NAL是不是SPS或则PPS，是的话进行复制相关参数到AVC结构体中保存，不是的话直接返回；
	if (1 == r && mp4->update)
		*mp4->update = 1;  // 表示有 SPS或则 PPS 发生了更新
	else if (r < 0)
		mp4->errcode = r;  // 如果出错，记录错误码
	
	// IDR-1, B/P-2, other-0
	if (mp4->vcl && 1 <= nalutype && nalutype <= H264_NAL_IDR)
		*mp4->vcl = nalutype == H264_NAL_IDR ? 1 : 2;

	if (mp4->capacity >= mp4->bytes + bytes + 4)
	{
		mp4->out[mp4->bytes + 0] = (uint8_t)((bytes >> 24) & 0xFF);
		mp4->out[mp4->bytes + 1] = (uint8_t)((bytes >> 16) & 0xFF);
		mp4->out[mp4->bytes + 2] = (uint8_t)((bytes >> 8) & 0xFF);
		mp4->out[mp4->bytes + 3] = (uint8_t)((bytes >> 0) & 0xFF);     // 存起来NAL的大小
		memmove(mp4->out + mp4->bytes + 4, nalu, bytes);    // 将 nalu 的内容，考到 buffer 中进行缓存，buffer只需要可以装下一帧数据的大小即可；
		mp4->bytes += bytes + 4;
	}
	else
	{
		printf("[ %s | %d ]buffer memory size deficiency \n",__FILE__,__LINE__);
		mp4->errcode = -1;
	}
}
// 如果NAL是NON-VCL,则将SPS   PPS 等参数拷贝到mpeg4_avc_t中存起来，如果是VCL数据，直接拷贝到缓存区存起来
/*
 data：  | SPS | PPS | SEI | VCL | VCL | VCL |
 bytes： data 的大小
 out: 缓存区
 size：缓存区大小
*/
// avc ---> h -----> mp4
// mpeg4_avc_t ---> h264_annexbtomp4_handle_t -----> h264_annexbtomp4_handle_t ----> mpeg4_avc_t
int h264_annexbtomp4(struct mpeg4_avc_t* avc, const void* data, size_t bytes, void* out, size_t size, int* vcl, int* update)
{
	struct h264_annexbtomp4_handle_t h;
	memset(&h, 0, sizeof(h));
	h.avc = avc;            // avc元数据参数结构体
	h.vcl = vcl;            // 0
	h.update = update;      // 0
	h.out = (uint8_t*)out;  // buffer
	h.capacity = size;      // buffer size
	if (vcl) *vcl = 0;
	if (update) *update = 0;
	// 这里传入的 data 是
	mpeg4_h264_annexb_nalu(data, bytes, h264_handler, &h); // 传入 | SPS | PPS | SEI | VCL | VCL | VCL |
	avc->nalu = 4;
	return 0 == h.errcode ? (int)h.bytes : 0;
}

// 判断这个nul是不是一帧新的画面或则是不是元数据；是的话返回1 不是返回0
/*
@
@   1  ： 一个非IDR的条带
@	2  ： 编码条带数据分割块A
@	3  ： 编码条带数据分割块B
@	4  ： 编码条带数据分割块C
@	5  ： IDR的图像编码条带
@	6  ： 辅助增强信息
@	7  ： 序列参数集
@	8  ： 图像参数集
@	9  ： 访问单元的分隔符
*/
int h264_is_new_access_unit(const uint8_t* nalu, size_t bytes)
{
    enum { NAL_NIDR = 1, NAL_PARTITION_A = 2, NAL_IDR = 5, NAL_SEI = 6, NAL_SPS = 7, NAL_PPS = 8, NAL_AUD = 9, };
    
    uint8_t nal_type;
    
    if(bytes < 2)
        return 0;
    
    nal_type = nalu[0] & 0x1f;    // 获取NAL的类型
    
    //  NAL和编码图像的顺序以及访问单元的关联------如果当前的 NALU 中的数据是元数据，返回 1
    if(NAL_AUD == nal_type || NAL_SPS == nal_type || NAL_PPS == nal_type || NAL_SEI == nal_type || (14 <= nal_type && nal_type <= 18))
        return 1;
    
    // 检测主编码图像的第一个VCL       
    if(NAL_NIDR == nal_type || NAL_PARTITION_A == nal_type || NAL_IDR == nal_type)
    {
        // Live555 H264or5VideoStreamParser::parse
        // 最高位表示它是不是一个新的 存储单元
        return (nalu[1] & 0x80) ? 1 : 0; // 当是一个新帧的VCL单元，则返回1
    }
    
    return 0;
}


static void mpeg4_h264_bitstream_format_test(void)
{
	const uint8_t bs3[] =   { 0x00,0x00,0x01,0x67,0x42,0xe0,0x1e,0xab,0xcd, };
	const uint8_t bs4[] =   { 0x00,0x00,0x00,0x01,0x67,0x42,0xe0,0x1e,0xab,0xcd, };
	const uint8_t bs5[] =   { 0x00,0x00,0x00,0x00,0x01,0x67,0x42,0xe0,0x1e,0xab,0xcd, };
	const uint8_t avcc3[] = { 0x00,0x00,0x06,0x67,0x42,0xe0,0x1e,0xab,0xcd, };
	const uint8_t avcc4[] = { 0x00,0x00,0x00,0x06,0x67,0x42,0xe0,0x1e,0xab,0xcd, };
	assert(0 == mpeg4_h264_bitstream_format(bs3, sizeof(bs3)));
	assert(0 == mpeg4_h264_bitstream_format(bs4, sizeof(bs4)));
	assert(0 == mpeg4_h264_bitstream_format(bs5, sizeof(bs5)));
	assert(3 == mpeg4_h264_bitstream_format(avcc3, sizeof(avcc3)));
	assert(4 == mpeg4_h264_bitstream_format(avcc4, sizeof(avcc4)));
}

static void mpeg4_annexbtomp4_test2(void)
{
	const uint8_t sps[] =  { 0x00,0x00,0x00,0x01,0x67,0x42,0xe0,0x1e,0xab,0xcd, };
	const uint8_t pps[] =  { 0x00,0x00,0x00,0x01,0x28,0xce,0x3c,0x80 };
	const uint8_t sps1[] = { 0x00,0x00,0x00,0x01,0x67,0x42,0xe0,0x1e,0x4b,0xcd, 0x01 };
	const uint8_t pps1[] = { 0x00,0x00,0x00,0x01,0x28,0xce,0x3c,0x80, 0x01 };
	const uint8_t sps2[] = { 0x00,0x00,0x00,0x01,0x67,0x42,0xe0,0x1e,0xab };
	const uint8_t pps2[] = { 0x00,0x00,0x00,0x01,0x28,0xce,0x3c };

	int vcl, update;
	uint8_t buffer[128];
	struct mpeg4_avc_t avc;
	memset(&avc, 0, sizeof(avc));

	h264_annexbtomp4(&avc, sps, sizeof(sps), buffer, sizeof(buffer), &vcl, &update);
	assert(0 == vcl && 1 == update);
	h264_annexbtomp4(&avc, pps, sizeof(pps), buffer, sizeof(buffer), &vcl, &update);
	assert(0 == vcl && 1 == update && 1 == avc.nb_sps && avc.sps[0].bytes == sizeof(sps)-4 && 0 == memcmp(avc.sps[0].data, sps+4, sizeof(sps) - 4) && 1 == avc.nb_pps && avc.pps[0].bytes == sizeof(pps) - 4 && 0 == memcmp(avc.pps[0].data, pps+4, sizeof(pps) - 4));

	h264_annexbtomp4(&avc, sps1, sizeof(sps1), buffer, sizeof(buffer), &vcl, &update);
	assert(0 == vcl && 1 == update && 2 == avc.nb_sps && avc.sps[0].bytes == sizeof(sps) - 4 && avc.sps[1].bytes == sizeof(sps1) - 4 && 0 == memcmp(avc.sps[0].data, sps+4, sizeof(sps) - 4) && 0 == memcmp(avc.sps[1].data, sps1 + 4, sizeof(sps1) - 4) && 1 == avc.nb_pps && avc.pps[0].bytes == sizeof(pps) - 4 && 0 == memcmp(avc.pps[0].data, pps + 4, sizeof(pps) - 4));
	
	h264_annexbtomp4(&avc, pps1, sizeof(pps1), buffer, sizeof(buffer), &vcl, &update);
	assert(0 == vcl && 1 == update && 2 == avc.nb_sps && avc.sps[0].bytes == sizeof(sps) - 4 && avc.sps[1].bytes == sizeof(sps1) - 4 && 0 == memcmp(avc.sps[0].data, sps + 4, sizeof(sps) - 4) && 0 == memcmp(avc.sps[1].data, sps1 + 4, sizeof(sps1) - 4) && 1 == avc.nb_pps && avc.pps[0].bytes == sizeof(pps1) - 4 && 0 == memcmp(avc.pps[0].data, pps1 + 4, sizeof(pps1) - 4));
	
	h264_annexbtomp4(&avc, sps2, sizeof(sps2), buffer, sizeof(buffer), &vcl, &update);
	assert(0 == vcl && 1 == update && 2 == avc.nb_sps && avc.sps[0].bytes == sizeof(sps2) - 4 && avc.sps[1].bytes == sizeof(sps1) - 4 && 0 == memcmp(avc.sps[0].data, sps2 + 4, sizeof(sps2) - 4) && 0 == memcmp(avc.sps[1].data, sps1 + 4, sizeof(sps1) - 4) && 1 == avc.nb_pps && avc.pps[0].bytes == sizeof(pps1) - 4 && 0 == memcmp(avc.pps[0].data, pps1 + 4, sizeof(pps1) - 4));
	
	h264_annexbtomp4(&avc, pps2, sizeof(pps2), buffer, sizeof(buffer), &vcl, &update);
	assert(0 == vcl && 1 == update && 2 == avc.nb_sps && avc.sps[0].bytes == sizeof(sps2) - 4 && avc.sps[1].bytes == sizeof(sps1) - 4 && 0 == memcmp(avc.sps[0].data, sps2 + 4, sizeof(sps2) - 4) && 0 == memcmp(avc.sps[1].data, sps1 + 4, sizeof(sps1) - 4) && 1 == avc.nb_pps && avc.pps[0].bytes == sizeof(pps2) - 4 && 0 == memcmp(avc.pps[0].data, pps2 + 4, sizeof(pps2) - 4));
}

void mpeg4_annexbtomp4_test(void)
{
	const uint8_t sps[] = { 0x67,0x42,0xe0,0x1e,0xab };
	const uint8_t pps[] = { 0x28,0xce,0x3c,0x80 };
	const uint8_t annexb[] = { 0x00,0x00,0x00,0x01,0x67,0x42,0xe0,0x1e,0xab, 0x00,0x00,0x00,0x01,0x28,0xce,0x3c,0x80,0x00,0x00,0x00,0x01,0x65,0x11 };
	uint8_t output[256];
	int vcl, update;

	struct mpeg4_avc_t avc;
	memset(&avc, 0, sizeof(avc));
	assert(h264_annexbtomp4(&avc, annexb, sizeof(annexb), output, sizeof(output), &vcl, &update) > 0);
	assert(1 == avc.nb_sps && avc.sps[0].bytes == sizeof(sps) && 0 == memcmp(avc.sps[0].data, sps, sizeof(sps)));
	assert(1 == avc.nb_pps && avc.pps[0].bytes == sizeof(pps) && 0 == memcmp(avc.pps[0].data, pps, sizeof(pps)));
	assert(vcl == 1);

	mpeg4_annexbtomp4_test2();
	mpeg4_h264_bitstream_format_test();
}



























